﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ParserTree
{
    public class ParserTree
    {
        Scanner.Token currentToken;


        public TreeNode1 parse(Scanner.Scanner newScanner)
        {
            this.myScanner = newScanner;
            currentToken = newScanner.GetNextToken();
            TreeNode1 Node = new TreeNode1();
            Node = this.Start();
            Node.convert();
            if (currentToken.TokenType == Scanner.TokenType.EndFile)
            {
                return Node;
            }
            else
            {
                return null;
            }
        }
        public TreeNode1 Start()
        {
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.program;
            Node.left = this.StmtSequence();
            Node.convert();
            return Node;
        }
        private TreeNode1 StmtSequence()
        {
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.statmSeq;
            bool result = false;
            Node.left = this.Statement();
            if (currentToken.TokenType == Scanner.TokenType.SemiColon)
            {
                result = this.Match(Scanner.TokenType.SemiColon);
                if (result == true)
                {
                    Node.right = this.StmtSequence();
                }
            }
            else
            {
                Node.convert();
                return Node;
            }
            Node.convert();
            return Node;
        }
        private TreeNode1 Statement()
        {
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.Statment;
            Node.convert();
            if (currentToken.TokenType == Scanner.TokenType.Write)
            {
                return this.WriteStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.Read)
            {
                return this.ReadStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.Repeat)
            {
                return this.RepeatStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.If)
            {
                return this.IfStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.ID)
            {
                return this.AssignStmt();
            }
            else
            {
                return null;
            }
        }
        private TreeNode1 AssignStmt()
        {
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.assignNode;
            Node.Value = this.currentToken.Lexem;
            bool result = this.Match(Scanner.TokenType.ID);
            if (result == true)
            {
                result = this.Match(Scanner.TokenType.Assign);
                if (result == true)
                {
                    Node.left = this.Experation();
                }
            }
            Node.convert();
            return Node;
        }
        private TreeNode1 IfStmt()
        {
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.ifNode;
            bool result = this.Match(Scanner.TokenType.If);
            if (result == true)
            {
                Node.left = this.Experation();
                if (result == true)
                {
                    result = this.Match(Scanner.TokenType.Then);
                    if (result == true)
                    {
                        Node.middel = this.StmtSequence();
                        switch (this.currentToken.TokenType)
                        {
                            case Scanner.TokenType.End:
                                {
                                    result = this.Match(Scanner.TokenType.End);
                                }
                                break;
                            case Scanner.TokenType.Else:
                                {
                                    result = this.Match(Scanner.TokenType.Else);
                                    if (result == true)
                                    {
                                        Node.right = this.StmtSequence();
                                        if (result == true)
                                        {
                                            result = this.Match(Scanner.TokenType.End);
                                        }
                                    }
                                }
                                break;
                            default:
                                {
                                    //return this.Reject();
                                }
                                break;
                        }
                        Node.convert();
                        return Node;
                    }
                }
            }
            Node.convert();
            return Node;
        }
        private TreeNode1 RepeatStmt()
        {
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.repeatNode;

            bool result = this.Match(Scanner.TokenType.Repeat);
            if (result == true)
            {
                Node.left = this.StmtSequence();
                if (result == true)
                {
                    result = this.Match(Scanner.TokenType.Until);
                    if (result == true)
                    {
                        Node.right = this.Experation();
                    }
                }
            }
            Node.convert();
            return Node;
        }
        private TreeNode1 ReadStmt()
        {
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.readNode;

            bool result = this.Match(Scanner.TokenType.Read);
            if (result == true)
            {
                Node.Value = this.currentToken.Lexem;
                result = this.Match(Scanner.TokenType.ID);
            }
            Node.convert();
            return Node;
        }
        private TreeNode1 WriteStmt()
        {
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.writeNode;

            bool result = this.Match(Scanner.TokenType.Write);
            if (result == true)
            {
                Node.left = this.Experation();
            }
            Node.convert();
            return Node;
        }
        public TreeNode1 Experation()
        {
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.Exp;
            Node.left = this.SimpleExp();
            while ((currentToken.TokenType == Scanner.TokenType.Equal || currentToken.TokenType == Scanner.TokenType.LessThan))
            {

                Node.middel = new TreeNode1();
                Node.middel = this.ComparisonOper();

                Node.right = new TreeNode1();
                Node.right = this.SimpleExp();

            }
            Node.convert();
            return Node;
        }
        private TreeNode1 ComparisonOper()
        {
            bool result;
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.comparisonNode;

            if (currentToken.TokenType == Scanner.TokenType.LessThan)
            {
                result = this.Match(Scanner.TokenType.LessThan);
                Node.Value = "<";
            }
            else if (currentToken.TokenType == Scanner.TokenType.Equal)
            {
                result = this.Match(Scanner.TokenType.Equal);
                Node.Value = "=";
            }
           
            Node.convert();
            return Node;
        }
        private TreeNode1 SimpleExp()
        {
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.simpleExp;
            Node.left = this.Term();

            if (currentToken.TokenType == Scanner.TokenType.Plus || currentToken.TokenType == Scanner.TokenType.Minus)
            {
                Node.middel = this.AddOper();
                Node.right = SimpleExp();
            }
            else
            {
                Node.convert();
                return Node;
            }
           
            Node.convert();
            return Node;
        }
        private TreeNode1 AddOper()
        {
            bool result;
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.operationNode;

            if (this.currentToken.TokenType == Scanner.TokenType.Minus)
            {
                result = this.Match(Scanner.TokenType.Minus);
                Node.Value = "-";
            }
            else if (this.currentToken.TokenType == Scanner.TokenType.Plus)
            {
                result = this.Match(Scanner.TokenType.Plus);
                Node.Value = "+";
            }
            
            Node.convert();
            return Node;
        }
        public TreeNode1 Term()
        {
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.term;
            Node.left = this.Factor();
            if (currentToken.TokenType == Scanner.TokenType.Times)
            {
                Node.middel = new TreeNode1();
                Node.middel.Type = TreeNode1.NodeType.MulOpNode;
                Node.middel.Value = "*";
                Node.middel.convert();
            }

            while (currentToken.TokenType == Scanner.TokenType.Times)
            {
                bool result = Match(Scanner.TokenType.Times);
                if (result == true)
                {
                    Node.right = this.Term();
                }
            }
            Node.convert();
            return Node;

        }
        private TreeNode1 Factor()
        {
            bool result;
            TreeNode1 Node = new TreeNode1();
            Node.Type = TreeNode1.NodeType.factor;
            switch (currentToken.TokenType)
            {
                case Scanner.TokenType.LeftParentheses:
                    {
                        result = this.Match(Scanner.TokenType.LeftParentheses);
                        if (result == true)
                        {
                            Node.left = new TreeNode1();
                            Node.left = this.Experation();
                            if (result == true)
                            {
                                result = this.Match(Scanner.TokenType.RightParentheses);
                            }
                        }
                    }
                    break;
                case Scanner.TokenType.Num:
                    {
                        Node.left = new TreeNode1();
                        Node.left.Value = this.currentToken.Lexem;
                        Node.left.Type = TreeNode1.NodeType.num;
                        Node.left.convert();
                        result = this.Match(Scanner.TokenType.Num);
                    }
                    break;
                case Scanner.TokenType.ID:
                    {

                        Node.left = new TreeNode1();
                        Node.left.Type = TreeNode1.NodeType.identefier;
                        Node.left.Value = this.currentToken.Lexem;
                        Node.left.convert();
                        result = this.Match(Scanner.TokenType.ID);
                    }
                    break;
                default:
                    {
                    }
                    break;
            }
            Node.convert();
            return Node;
        }
        public bool Match(Scanner.TokenType s)
        {
            if (currentToken.TokenType == s)
            {
                this.currentToken = this.myScanner.GetNextToken();
                return this.Accept();
            }
            else
            {
                return this.Reject();
            }
        }
        private bool Accept()
        {
            return true;
        }
        private bool Reject()
        {
            return false;
        }
        public Scanner.Scanner myScanner { get; set; }
    }
}
